import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HttpServer {


    public static void main(String[] args) throws Exception {
        String port=args[0];

        try {
            startHttpServer(Integer.valueOf(port));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void startHttpServer(int port) throws Exception {
        ServerSocket ss = new ServerSocket(port);
        System.out.println("启动服务器....");
        while (true) {
            Socket s = ss.accept();
            try {
                //读取客户端发送来的消息
                String code = parseInputStreamToString(s.getInputStream());
                System.out.println("淘宝口令：" + code);
                insertLog(code);
                String redirectUrl ;
                redirectUrl = getParseUrl(code);
                insertLog(redirectUrl);
                System.out.println("最终redirectUrl="+redirectUrl);
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                if (!"".equals(redirectUrl)) {
                    bw.write(getSucceedResponeInfo(redirectUrl));
                }else{
                    bw.write(getErroresponeInfo("获取失败！"));
                }
                bw.flush();
            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                if (s != null) {
                    s.close();
                }
            }
        }
    }

    public static String parseInputStreamToString(InputStream in) throws IOException, InterruptedException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String retStr=reader.readLine();
        retStr = retStr.substring(10, retStr.length());
        retStr=URLDecoder.decode(retStr, "UTF-8");
        System.out.println(retStr);
        return retStr;
    }

    public static String getParseUrl(String code){
        if (code == null) {
            return "";
        }
        Matcher matcher = Pattern.compile("https:\\S*").matcher(code);
        String sourceUrl ;
        if (matcher.find()) {
            sourceUrl=matcher.group(0);
        }else{
            return "";
        }
        Map<String,String> respond=getRespond(sourceUrl);
        if (respond != null) {
            String body=respond.get("body");
            Matcher matcher2= Pattern.compile("var url = 'https://\\S*';").matcher(body);
            String url ;
            if (matcher2.find()) {
                url=matcher2.group(0);
            }else{
                return "";
            }
            url = url.substring(11, url.length() - 2);
            Map<String,String> respond2=getRespond(url);
            if (respond2 != null && respond2.get("redirectUrl") != null) {
                String redirectUrl = respond2.get("redirectUrl");
                if (!"".equals(redirectUrl)) {
                    redirectUrl=redirectUrl.replace("http:", "https:");
                    return redirectUrl;
                }
            }else{
                return "";
            }
        }
        return "";
    }
    public static String getSucceedResponeInfo(String retStr) {
        StringBuffer rep = new StringBuffer();
        //状态行
        rep.append("HTTP/1.1 200 ok\r\n");
        //首部行
        rep.append("Access-Control-Allow-Origin: *\r\n");
        rep.append("Access-Control-Allow-Headers: *\r\n");
        rep.append("Access-Control-Allow-Methods: GET\r\n");
        rep.append("Data:" + new Date() + "\r\n");
        //空行，表示后面的内容为返回内容
        rep.append("\r\n");
        //返回内容
        rep.append(retStr);
        return rep.toString();
    }

    public static String getErroresponeInfo(String retStr) {
        StringBuffer rep = new StringBuffer();
        //状态行
        rep.append("HTTP/1.1 500 error\r\n");
        //首部行
        rep.append("Access-Control-Allow-Origin: *\r\n");
        rep.append("Access-Control-Allow-Headers: *\r\n");
        rep.append("Access-Control-Allow-Methods: GET\r\n");
        rep.append("Data:" + new Date() + "\r\n");
        //空行，表示后面的内容为返回内容
        rep.append("\r\n");
        //返回内容
        rep.append(retStr);
        return rep.toString();
    }

    public static Map<String,String> getRespond(String url){
        System.setProperty("https.protocols", "TLSv1.1");
        String body = "";
        String redirectUrl = "";
        try {

            HttpURLConnection conn=getHttpsURLConnection(url);
            int status = conn.getResponseCode();
            if (status != HttpsURLConnection.HTTP_OK) {
                if (status == HttpsURLConnection.HTTP_MOVED_TEMP|| status == HttpsURLConnection.HTTP_MOVED_PERM|| status == HttpsURLConnection.HTTP_SEE_OTHER)
                    redirectUrl=conn.getHeaderField("Location");
            }else{
                redirectUrl = url;
            }

            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer html = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                html.append(inputLine);
            }
            in.close();
            body = html.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, String> retMap = new HashMap<>();
        retMap.put("body", body);
        retMap.put("redirectUrl", redirectUrl);
        return retMap;
    }

    private static HttpURLConnection getHttpsURLConnection(String url) throws IOException {
        System.out.println("connect==>"+url);
        String protocol = url.substring(0, 5);
        URL obj = new URL(url);
        HttpURLConnection conn=null;
        if ("https".equals(protocol)) {
            HttpsURLConnection httpsConn = (HttpsURLConnection) obj.openConnection();
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext ctx = null;
            try {
                ctx = SSLContext.getInstance("TLS");
                ctx.init(null, tm, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            httpsConn.setSSLSocketFactory(ctx.getSocketFactory());
            httpsConn.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; }
            });
            conn = httpsConn;
        }else{
            conn=(HttpURLConnection) obj.openConnection();
        }
        conn.setReadTimeout(5000);
        conn.addRequestProperty("User-Agent", "Mozilla");

        return conn;
    }

    public static class MyX509TrustManager extends X509ExtendedTrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) {
        }
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1, Socket arg2) {
        }
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1, SSLEngine arg2) {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1, Socket arg2) {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1, SSLEngine arg2) {
        }
    }
    
    private static BufferedWriter bufferedWriter;

    static {
        try {
            File logFile = new File("./log.txt");
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile)));
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void insertLog(String log) {
        try {
            bufferedWriter.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")) +"--->"+log);
            bufferedWriter.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}